#include "Dual_Link_List.h"
#include "stdlib.h"

struct _ListNode {
	struct _ListNode* next;
	struct _ListNode* prior;
	void* data;
	void* additional_message;
};



//Get the Node with specific index;
//Return: return the pointer to this node. If the index is illegal or the node cannot be found, NULL will be returned.
p_ListNode get_node(p_ListNode list, int index) {
	if((index<0) || (index>get_length(list)-1)) {
		printf("The index is illegal!\n");
		return NULL;
	}

	p_ListNode p = list->next;
	if(p == list) {
		printf("This is the empty list, cannot get the node!\n");
		return NULL;
	}
	int count = 0;
	while((count < index) && (p != list)) {
		p = p->next;
		count++;
	}
	if(p != list) {
		return p;
	}
	else {
		printf("cannot find the node in this list\n");		
		return NULL;
	}
}

// Get the Node with specific index, 
// Return:If the element can be found, it will return 0, or it will return -1.
int8_t get_element(p_ListNode list, int index, void* data) {
	p_ListNode p = get_node(list,index);
	if(!p) {
		return -1;
	}
	else {
		data = p->data;
		return 0;
	}
}

// get the length of link list;
// Return: length of link list.
int get_length(p_ListNode list) {
	p_ListNode p = list->next;
	int length = 0;
	while(p != list){
		p = p->next;
		length++;
	}
	return length;
}

//Create a link list node with a given data
//Return:return a pointer pointed to created node if 0, return null if fail
p_ListNode create_node(void* data)
{
	p_ListNode p = (struct _ListNode*)malloc(sizeof(struct _ListNode));
	if(!p) {
		printf("fail to create a link list node!\n");
		return NULL;
	}
	p->data = data;
	p->additional_message = NULL;
	p->prior = p;
	p->next = p;
	return p;
}

// insert a node with a given element into a link list before a specific index
// Return: return SUCEESS if 0 to insert node, or it will return -1.
int8_t insert_node(p_ListNode list, int index, void* data) {
	if((index < 0) || (index > get_length(list))) {
		printf("the laction is illegal!\n");
		return -1;
	}

	/*p_ListNode p =(p_ListNode)malloc(sizeof(ListNode));
	if(!p) {
		return -1;
	}
	p->data = data;
	p->next = NULL;
	p->prior = NULL;
	*/

	p_ListNode p = create_node(data);
	if(!p) {
		return -1;
	}

	p_ListNode q = NULL;
	if(index == get_length(list)) {
		q = list;
	}
	else {
		q = get_node(list,index);
		if(!q) {
			return -1;
		}
	}

	q->prior->next = p;
	p->prior = q->prior;
	p->next = q;
	q->prior = p;

	return 0;
}

// delete a node from a link list with a specific index, the element of this deleted node will be return by para e.
// Return: return 0 if delete 0fully, or return -1.
int8_t delete_node_by_index(p_ListNode list, int index, void* data) {
	if((index < 0) || (index > get_length(list)-1)) {
		return -1;
	}

	p_ListNode p = get_node(list,index);

	data = p->data;
	p_ListNode q = p->next;
	p->prior->next = q;
	q->prior = p->prior;

	free(p);

	return 0;
}

// delete a node from a link list with a specific index
// return 0 if delete successfully, or return -1
int8_t delete_node_by_pointer(p_ListNode p_node)
{
	// see if p_node is the header pointer
	if(p_node->next == p_node && p_node->prior == p_node) {
		printf("&delete_node_by_pointer: this node is header node of"
				"this link list, plz use destory_link_list to destory"
				"this link list.\n");
		return -1;
	}

	p_node->prior->next = p_node->next;
	p_node->next->prior = p_node->prior;

	free(p_node);

	return 0;
}

// Destroy the link list
// Return: void
void destroy_link_list(p_ListNode list) {
	p_ListNode p = list->next;
	p_ListNode q = NULL;
	while(p != list) {
		q = p->next;
		p->prior->next = q;
		q->prior = p->prior;
		free(p);
		p = q;
	}
	free(list);
	printf("The link list has been destroyed!\n");
}

// print all of nodes in link list sequencely to the screen
// Return: void
void print_list(p_ListNode list, ListDataPrintFunc print_data) {
	p_ListNode p = list->next;
	if(p == list) {
		printf("The list is empty!\n");
	}
	else {
		printf("The list is: \n");
		while(p != list) {
			print_data(p->data);
			p = p->next;
		}
	}
}

// Set the additional message for node.
// Return: return 1 if success, return -1 if fail.
int8_t set_additional_message_for_node(p_ListNode p_node, void* message)
{
	if(NULL == p_node) {
		printf("The pointer to node is empty,"
				"cannot set the addition message to this node\n");
		return -1;
	}

	p_node->additional_message = message;

	return 1;
}

p_ListNode get_next_node(p_ListNode p_node)
{
	return p_node->next;
}

void* get_additional_message(p_ListNode p_node)
{
	return p_node->additional_message;
}

void* get_data(p_ListNode p_node)
{
	return p_node->data;
}
